/**
	Pulsar engine. Additional include file.
	Thread safe queue.

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

namespace pl
{

enum QueuePushMode
{
	QUEUE_PUSH_MODE_REPLACE,
	QUEUE_PUSH_MODE_FAIL
};


class QueueBase
{
public:
	class Iterator
	{
	public:
		explicit Iterator(QueueBase& q);
		~Iterator();

		bool isFinished();
		const void* getContent(int& size);

	private:
		QueueBase& _q;
		int _curPos;
		pl_int32 _curBlockSize;
		void* _curBlockPtr;
	};

	/// Ctor
	explicit QueueBase(int bufSize, QueuePushMode mode);

	/// Dtor
	~QueueBase();

	/// Calculate size of queue required to store N packets
	static int calcBufSize(int packetSize, int nMaxPackets)
	{
		return (packetSize + 4)* nMaxPackets + 8;
	}

	/// Push an item to	queue
	bool push(const void* buf, int size);

	/// Pop an item from queue
	bool pop(void* buf, int& size);

	/// Allocate space, user will place data later
	void* alloc(int size);

	/// Get count of objects
	inline pl_uint32 count() const
	{
		PL_ASSERTW(_count >= 0, PL_T("Internal error"));
		return _count;
	}

	/// Remove all objects
	void clear();

protected:
	/// Internal allocation (without lock)
	void* _alloc(int size);

protected:
	int _bufSize;
	pl_int8* _buffer;
	QueuePushMode _mode;
	int _head;
	int _tail;
	pl::CriticalSection _cs;
	pl_uint32 _count;

	bool _scrollHead(int posStart, int posEnd);
	void* _pop(int& size, int &pos);
};

/**

*/
template<class T, pl_uint32 N> class Queue : protected QueueBase
{
public:
	Queue(QueuePushMode pushMode) :
	QueueBase((sizeof(T) + sizeof(int))*N, pushMode)
	{
		return;
	}

	~Queue()
	{
		return;
	}

	bool push(const T& element)
	{
		return QueueBase::push(&element, sizeof(T));
	}

	bool pop(T& element)
	{
		int size = sizeof(T);
		return QueueBase::pop(&element, size);

	}

	bool isFull() const
	{
		return (count() == N);
	}

	class Iterator : private pl::QueueBase::Iterator
	{
	public:
		Iterator(Queue<T, N>& q) :
		pl::QueueBase::Iterator(q)
		{
			return;
		}

		const T& operator*()
		{
			int size;
			const void* data = getContent(size);
			return *(const T*)data;
		}
	};

};

} // namespace pl

//
// End of file 'pulsar_queue.h'
//
